from flask import current_app, jsonify, abort, render_template, session, g, request

from info import db
from info.common import user_login_data
from info.constants import HOME_PAGE_MAX_NEWS
from info.models import News, Comment, CommentLike
from info.modules.news import news_blu
from info.utils.response_code import RET, error_map


@news_blu.route('/<int:news_id>')
@user_login_data
def news_detail(news_id):
    news = None
    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    if not news:
        return abort(404)

    news.clicks += 1

    rank_list = []
    try:
        rank_list = News.query.order_by(News.clicks.desc()).limit(HOME_PAGE_MAX_NEWS).all()
    except BaseException as e:
        current_app.logger.error(e)
    rank_list = [news.to_basic_dict() for news in rank_list]

    is_collected = False
    user = g.user
    like_comments_id = []
    if user:
        if news in user.collection_news:
            is_collected = True

        like_comments = CommentLike.query.filter_by(user_id=user.id).all()
        like_comments_id = [like_comment.comment_id for like_comment in like_comments]

    user = g.user.to_dict() if g.user else None

    comments = Comment.query.filter_by(news_id=news_id).order_by(Comment.create_time.desc()).all()
    comments = [comment.to_dict() for comment in comments]

    return render_template("news/detail.html", news=news.to_dict(), rank_list=rank_list, user=user,
                           is_collected=is_collected, comments=comments, like_comments_id=like_comments_id)


@news_blu.route('/news_collect', methods=["POST"])
@user_login_data
def news_collect():
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg=error_map[RET.SESSIONERR])

    news_id = request.json.get("news_id")
    action = request.json.get("action")

    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        news_id = int(news_id)
    except BaseException as e:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    if action not in ["collect", "cancel_collect"]:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    if not news:
        return jsonify(errno=RET.DATAERR, errmsg=error_map[RET.DATAERR])

    if action == "collect":
        if news not in user.collection_news:
            user.collection_news.append(news)
    else:
        if news in user.collection_news:
            user.collection_news.remove(news)

    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


@news_blu.route("/news_comment", methods=["POST"])
@user_login_data
def news_comment():
    user = g.user
    if not user:
        return jsonify(errno=RET.USERERR, errmsg=error_map[RET.USERERR])

    news_id = request.json.get("news_id")
    comment = request.json.get("comment")
    parent_id = request.json.get("parent_id")

    if not all([news_id, comment]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        news_id = int(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    if not news:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    new_comment = Comment()
    new_comment.news_id = news_id
    new_comment.content = comment
    new_comment.user_id = user.id

    if parent_id:
        try:
            parent_id = int(parent_id)
        except BaseException as e:
            current_app.loggrt.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
        new_comment.parent_id = parent_id

    try:
        db.session.add(new_comment)
        db.session.commit()
    except BaseException as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    data = new_comment.to_dict()

    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=data)


@news_blu.route("/comment_like", methods=["POST"])
@user_login_data
def comment_like():
    user = g.user

    if not user:
        return jsonify(errno=RET.USERERR, errmsg=error_map[RET.USERERR])

    comment_id = request.json.get("comment_id")
    action = request.json.get("action")

    if not all([comment_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        comment_id = int(comment_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    if action not in ["add", "remove"]:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        comment = Comment.query.get(comment_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    if action == "add":
        comment_like = CommentLike()
        comment_like.comment_id = comment_id
        comment_like.user_id = user.id

        try:
            db.session.add(comment_like)
            db.session.commit()
            comment.like_count += 1
        except BaseException as e:
            current_app.logger.error(e)
            db.session.rollback()
            return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    else:
        try:
            CommentLike.query.filter_by(comment_id=comment_id, user_id=user.id).delete()
            db.session.commit()
            comment.like_count -= 1
        except BaseException as e:
            current_app.logger.error(e)
            db.session.rollback()
            return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])
